
package com.vanda.db.cfg;
import java.io.InputStream;
import java.net.URI;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.vanda.db.exception.MappingException;
import com.vanda.db.util.MapUtils;
import com.vanda.db.util.XMLParser;
import com.vanda.util.Globals;
import com.vanda.util.LogFunc;

/**
 * 读取DB配置文件类 <br>
 * @author 王瑛 <br>
 * @version Version 1.00 <br>
 */
public class Configuration {
	/** 主配置文件路径 */
	private String _resource = null;
	/** 日志类 */
	private static Log log = LogFactory.getLog(Configuration.class);
	/** 保存配置文件类 */
	private static ConfigBean _bean = null;
	
	/** 
	 * 构造方法
	 *
	 */
	public Configuration() {
		_resource = Globals.getValue("db.config");
	}
	/**
	 * 构造方法
	 * @param resource 主配置文件位置
	 */
	public Configuration(String resource) {
		_resource = resource;
	}
	
	/**
	 * 取得配置文件数据
	 * @return
	 */
	public static ConfigBean getConfigBean() {
		return _bean;
	}
	
	/**
	 * 读取配置文件
	 * @throws Exception
	 */
	public void configure() throws Exception {
		InputStream stream = Environment.class.getResourceAsStream(_resource);
		if (stream == null) {
			log.error(_resource + " not found");
			throw new MappingException(_resource + " not found");
		}
		//解析xml文件
		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(stream);
		List list =
			document.selectNodes("/xql-configuration/hibernate-configuration");
		Iterator iter = list.iterator();
		while (iter.hasNext()) {
			Element hibernate = (Element) iter.next();
			String name = getAttribute(hibernate, "name", true);
			String resource = getAttribute(hibernate, "resource", true);
			ConfigBean.hibernate.put(name, resource);
		}
		LogFunc.info("Read hibernate-configuration success!");
		list = document.selectNodes("/xql-configuration/property");
		iter = list.iterator();
		while (iter.hasNext()) {
			Element property = (Element) iter.next();
			String name = getAttribute(property, "name", true);
			String value = getElement(property, true);
			ConfigBean.property.put(name, value);
		}
		
		String xqlConfigDir =
			(String) ConfigBean.property.get("xqlconfig_relative_dir");
		URI xqlConfigURI = null;
		//生成xqlConfig目录路径
		if (xqlConfigDir != null) {
			//sqlConfigURI =
			//	(new File(resourceURL, sqlConfigDir)).toURI().normalize();
			xqlConfigURI = new URI(xqlConfigDir);
			LogFunc.info("xqlConfigURI = " + xqlConfigURI);
		}
		
		LogFunc.info("Read property success!");
		list = document.selectNodes("/xql-configuration/mapping");
		iter = list.iterator();
		while (iter.hasNext()) {
			Element mapping = (Element) iter.next();
			String resource = getAttribute(mapping, "resource", true);
			String namespace = getAttribute(mapping, "namespace", true);
			MappingBean bean = readMappingXML(resource,xqlConfigURI);
			bean.setNamespace(namespace);
			ConfigBean.mapfiles.put(bean.getNamespace(), bean);
			LogFunc.info("Read mapping file[" + resource + "] success!");
		}
		setDefault();
	}
	
	/**
	 * 设置默认值
	 *
	 */
	private void setDefault() {
		HashMap map = ConfigBean.property;
		String num =
			MapUtils.getStringValue(map, Environment.PROPERTY_PAGE_ROW_NUM);
		//设置page_row_num默认为每页10条
		if (num == null) {
			map.put(Environment.PROPERTY_PAGE_ROW_NUM, "10");
		}
	}
	
	/**
	 * 读取xql配置文件
	 * @param resource
	 * @param dir
	 * @return
	 * @throws Exception
	 */
	private MappingBean readMappingXML(String resource,URI dir) throws Exception {
		MappingBean bean = new MappingBean();
		InputStream stream = getMappingStream(resource,dir);
		//解析xml文件
		SAXReader saxReader = new SAXReader();
		Document document = saxReader.read(stream);
		Element xqls = (Element) document.selectSingleNode("/xqls");
		List list = document.selectNodes("/xqls/xql");
		Iterator iter = list.iterator();
		while (iter.hasNext()) {
			Element xql = (Element) iter.next();
			MappingInfo info = new MappingInfo();
			info.setName(getAttribute(xql, "name", true));
			String type = getAttribute(xql, "type", false);
			if (type != null && !type.trim().equals("")) {
				info.setType(type);
			}
			String query = getAttribute(xql, "isQuery", false);
			if (query != null && !query.trim().equals("")) {
				try {
					info.setQuery(Boolean.getBoolean(query));
				} catch (Exception e) {
					log.error(
						"xql->isQuery:"
							+ query
							+ ",but should be \"true\" or \"false\"");
				}
			}
			String connection = getAttribute(xql, "connection", false);
			if (connection != null && !connection.trim().equals("")) {
				info.setConnection(connection);
			}
			List lstParam = xql.selectNodes("param");
			for (int i = 0; i < lstParam.size(); i++) {
				Element param = (Element) lstParam.get(i);
				String alias = getAttribute(param, "alias", true);
				String defClass = getAttribute(param, "defClass", true);
				info.getParams().put(alias, defClass);
			}
			Element retElement = (Element) xql.selectSingleNode("return");
			if (retElement != null) {
				info.setReturnClass(getAttribute(retElement, "defClass", true));
			}
			List lstContent = xql.selectNodes("content");
			for (int i = 0; i < lstContent.size(); i++) {
				Element content = (Element) lstContent.get(i);
				
				info.addContent(XMLParser.convert(getElement(content, true)));
			}
			Element countElement =
				(Element) xql.selectSingleNode("count-content");
			if (countElement != null) {
				info.setCountXQL(XMLParser.convert(getElement(countElement, true)));
			}
			bean.getMapping().put(info.getName(), info);
		}
		return bean;
	}
	
	/**
	 * 取得xml配置文件流
	 * @param path xml配置文件路径
	 * @return
	 * @throws MappingException
	 */
	private InputStream getMappingStream(String path) throws MappingException {
		LogFunc.info("Mapping resource: " + path);
		InputStream rsrc =
			Thread.currentThread().getContextClassLoader().getResourceAsStream(
				path);
		if (rsrc == null)
			rsrc = Environment.class.getClassLoader().getResourceAsStream(path);
		LogFunc.info("Environment.class.getClassLoader() rsrs = " + rsrc);
		if (rsrc == null)
			rsrc = Environment.class.getResourceAsStream(path);
		LogFunc.info("Environment.class rsrs = " + rsrc);
		if (rsrc == null)
			throw new MappingException("Resource: " + path + " not found");
		return rsrc;
	}
	
	/**
	 * 取得元素属性值
	 * @param element xml元素 
	 * @param name 属性名称
	 * @param nullCheck 是否做空检查,如果做空检查,则不能为空
	 * @return
	 * @throws MappingException
	 */
	private String getAttribute(
		Element element,
		String name,
		boolean nullCheck)
		throws MappingException {
		String value = element.attributeValue(name);
		if (nullCheck) {
			if (value == null || value.trim().equals("")) {
				log.error(
					element.getName() + "->" + name + ": must not be null!");
				throw new MappingException(
					element.getName() + "->" + name + ": must not be null!");
			}
		}
		return value;
	}
	
	/**
	 * 取得元素值
	 * @param element xml元素
	 * @param nullCheck 是否做空检查,如果做空检查,则不能为空
	 * @return
	 * @throws MappingException
	 */
	private String getElement(Element element, boolean nullCheck)
		throws MappingException {
		String value = element.getText();
		if (nullCheck) {
			if (value == null || value.trim().equals("")) {
				log.error(element.getName() + ": must not be null!");
				throw new MappingException(
					element.getName() + ": must not be null!");
			}
		}
		return value;
	}
	
	/**
	 * 取得dir+name的文件流
	 * @param name 文件名
	 * @param dir 文件目录
	 * @return
	 * @throws MappingException
	 */
	private InputStream getMappingStream(String name, URI dir)
		throws MappingException {
		InputStream rsrc = null;
		//如果为空，则取系统路径
		if (dir == null) {
			LogFunc.info("Mapping resource: " + name);
			rsrc =
				Thread
					.currentThread()
					.getContextClassLoader()
					.getResourceAsStream(
					name);
			if (rsrc == null)
				rsrc =
					Environment.class.getClassLoader().getResourceAsStream(
						name);
			if (rsrc == null)
				rsrc = Environment.class.getResourceAsStream(name);
		} else {
			try {

				rsrc = Environment.class.getResourceAsStream(dir+"/"+name);
				LogFunc.info("Mapping resource: " + (dir+"/"+name));
			} catch (Exception e) {
				throw new MappingException(
					"Resource: " + name + " not found",
					e);
			}
		}
		if (rsrc == null)
			throw new MappingException("Resource: " + name + " not found");
		return rsrc;
	}

}
